home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dme / keyboard.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  15KB  |  652 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6.  
  7. /*
  8.  *  KEYBOARD.C
  9.  *
  10.  *  Handle keyboard related stuff such as keyboard mappings.  Every time
  11.  *  a key is pressed, KEYCTL() is called with the code.  KEYCTL() remembers
  12.  *  which qualifier keys are currently held down, and when a non-qualifier
  13.  *  key is pressed finds the hash entry for the key.  If no hash entry
  14.  *  exists (e.g. you type a normal 'a') the default keymap is used.
  15.  */
  16.  
  17. #include "defs.h"
  18. #include <devices/keymap.h>
  19. #include <devices/console.h>
  20.  
  21. Prototype void keyctl (struct IntuiMessage *, int, unsigned short);
  22. Prototype void dealloc_hash (void);
  23. Prototype void resethash (void);
  24. Prototype int returnoveride (int);
  25. Prototype void addhash (ubyte, ubyte, ubyte, ubyte, ubyte *);
  26. Prototype int remhash (ubyte, ubyte, ubyte);
  27. Prototype char *keyspectomacro (char *);
  28. Prototype void do_map (void);
  29. Prototype void do_unmap (void);
  30. Prototype void do_clearmap (void);
  31. Prototype void do_savemap (void);
  32. Prototype void keyboard_init (void);
  33. Prototype unsigned char *cqtoa (int, int);
  34. Prototype int get_codequal (ubyte *, ubyte *, ubyte *);
  35.  
  36. typedef struct IOStdReq CIO;
  37.  
  38. #define QUAL_SHIFT   0x01
  39. #define QUAL_CTRL    0x02
  40. #define QUAL_AMIGA   0x04
  41. #define QUAL_ALT     0x08
  42. #define QUAL_LMB     0x10
  43. #define QUAL_MMB     0x20
  44. #define QUAL_RMB     0x40
  45.  
  46. #define HASHSIZE  64            /*    power of 2  */
  47. #define HASHMASK  (HASHSIZE-1)
  48.  
  49. typedef struct _HASH {
  50.     struct _HASH *next;     /* next hash   */
  51.     ubyte code;         /* keycode       */
  52.     ubyte mask;         /* qual. mask  */
  53.     ubyte qual;         /* qual. comp  */
  54.     ubyte stat;         /* string static? */
  55.     char *str;            /* command string */
  56. } HASH;
  57.  
  58. HASH *Hash[HASHSIZE];
  59.  
  60. struct Library *ConsoleDevice;
  61.  
  62. ubyte    ctoa[128];
  63. ubyte    cstoa[128];
  64.  
  65. void
  66. keyctl(im, code, qual)
  67. IMESS *im;
  68. USHORT qual;
  69. {
  70.     ubyte buf[256];
  71.     ubyte c2;
  72.     short blen = 0;
  73.  
  74.     code &= 0xFF;
  75.     if (im) {
  76.     uword oldQual = im->Qualifier;
  77.  
  78.     im->Qualifier &= ~IEQUALIFIER_REPEAT;
  79.     blen = DeadKeyConvert(im, buf+1, 254, NULL);
  80.     im->Qualifier = oldQual;
  81.     if (blen < 0)
  82.         return;
  83.     }
  84.     c2 = 0;
  85.     if (qual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  86.     c2 |= QUAL_SHIFT;
  87.     if (qual & (IEQUALIFIER_CONTROL))
  88.     c2 |= QUAL_CTRL;
  89.     if (qual & (IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND))
  90.     c2 |= QUAL_AMIGA;
  91.     if (qual & (IEQUALIFIER_LALT|IEQUALIFIER_RALT))
  92.     c2 |= QUAL_ALT;
  93.     if ((qual & IEQUALIFIER_CAPSLOCK) && blen == 1 && buf[1] >= 'a' && buf[1] <= 'z')
  94.     c2 |= QUAL_SHIFT;
  95.     if (qual & IEQUALIFIER_LEFTBUTTON)
  96.     c2 |= QUAL_LMB;
  97.     if (qual & IEQUALIFIER_MIDBUTTON)
  98.     c2 |= QUAL_MMB;
  99.     if (qual & (IEQUALIFIER_RBUTTON))
  100.     c2 |= QUAL_RMB;
  101.  
  102.     {
  103.     HASH *hash;
  104.     for (hash = Hash[code&HASHMASK]; hash; hash = hash->next) {
  105.         if (hash->code == code && (c2 & hash->mask) == hash->qual)
  106.         break;
  107.     }
  108.  
  109.     /*
  110.      *  Use hash entry only if not in command line mode, or if the
  111.      *  entry does not correspond to an alpha key.
  112.      */
  113.  
  114.     if (hash) {
  115.         if (c2 || !Comlinemode || blen > 1 || !ctoa[code]) {
  116.         strcpy(buf, hash->str);
  117.         do_command(buf);
  118.         return;
  119.         }
  120.     }
  121.     }
  122.  
  123.     /*
  124.      *    No hash entry
  125.      */
  126.  
  127.     if (blen == 1) {
  128.     buf[0] = '\'';
  129.     buf[2] = 0;
  130.     } else {
  131.     buf[0] = '\`';
  132.     buf[blen+1] = '\'';
  133.     }
  134.     if (blen)
  135.     do_command(buf);
  136. }
  137.  
  138. void
  139. dealloc_hash()
  140. {
  141.     HASH *hash, *hnext = NULL;
  142.     short i;
  143.  
  144.     for (i = 0; i < HASHSIZE; ++i) {
  145.     for (hash = Hash[i]; hash; hash = hnext) {
  146.         hnext = hash->next;
  147.         if (!hash->stat)
  148.         FreeMem(hash->str, strlen(hash->str)+1);
  149.         FreeMem(hash, sizeof(HASH));
  150.     }
  151.     Hash[i] = NULL;
  152.     }
  153. }
  154.  
  155. void
  156. resethash()
  157. {
  158.     short i;
  159.     CIO cio;
  160.     static const struct {
  161.     const char *from, *to;
  162.     } defmap[] = {
  163.     "esc",      "esc",
  164.     "c-esc",    "recall",
  165.     "return",   "ifelse b (return) (return insline) up firstnb down",
  166.     "enter",    "return",
  167.     "up",       "up",
  168.     "down",     "down",
  169.     "right",    "right",
  170.     "left",     "left",
  171.     "bs",       "bs",
  172.     "del",      "del",
  173.     "tab",      "tab",
  174.     "a-up",     "scrollup",
  175.     "a-down",   "scrolldown",
  176.     "a-r",      "nextr",
  177.     "a-u",      "while cl (tlate -32 right)",
  178.     "a-l",      "while cu (tlate +32 right)",
  179.     "s-up",     "top",
  180.     "s-down",   "bottom",
  181.     "s-right",  "last",
  182.     "s-left",   "first",
  183.     "s-tab",    "backtab",
  184.     "s-del",    "deline",
  185.     "s- ",      "( )",              /* shift space to space */
  186.     "c-1",      "goto block",
  187.     "c-c",      "",                 /* break.. map to a nop */
  188.     "c-l",      "wleft",
  189.     "c-r",      "wright",
  190.     "c-i",      "insertmode on",
  191.     "c-o",      "insertmode off",
  192.     "c-j",      "join",
  193.     "c-s",      "split first down",
  194.     "c-del",    "remeol",
  195.     "c-n",      "next",
  196.     "c-p",      "prev",
  197.     "c-/",      "escimm (find )",
  198.     "c-]",      "ref",
  199.     "c-[",      "ctags",
  200.     "c-g",      "escimm (goto )",
  201.     "c-up",     "pageup",
  202.     "c-down",   "pagedown",
  203.     "c-q",      "quit",
  204.     "c-f",      "reformat",
  205.     "c-w",      "wordwrap toggle",
  206.     "f1",       "escimm (insfile )",
  207.     "f2",       "escimm (newfile )",
  208.     "f3",       "escimm (newwindow newfile )",
  209.     "f6",       "saveold iconify",
  210.     "f7",       "escimm (bsave )",
  211.     "f8",       "saveold escimm (newfile )",
  212.     "f9",       "saveold",
  213.     "f10",      "saveold quit",
  214.     "c-b",      "block",
  215.     "c-u",      "unblock",
  216.     "a-d",      "bdelete",
  217.     "a-c",      "bcopy",
  218.     "a-m",      "bmove",
  219.     "a-s",      "bsource",
  220.     "a-S",      "unblock block block bsource",
  221.     "L-lmb",    "tomouse",      /*  left button                 */
  222.     "L-mmo",    "tomouse",      /*  mouse move w/left held down */
  223.     "R-rmb",    "iconify",      /*  right button                */
  224.     NULL, NULL
  225.     };
  226.  
  227.     dealloc_hash();
  228.     OpenDevice("console.device", -1, (struct IORequest *)&cio, 0);
  229.     ConsoleDevice = (struct Library *)cio.io_Device;
  230.     keyboard_init();
  231.     for (i = 0; defmap[i].from; ++i) {
  232.     ubyte code, qual;
  233.     if (get_codequal(defmap[i].from, &code, &qual))
  234.         addhash(code, 1, 0xFF, qual, defmap[i].to);
  235.     }
  236. }
  237.  
  238. returnoveride(n)
  239. {
  240.     HASH *hash;
  241.     static ubyte *str;
  242.     static int stat;
  243.  
  244.     for (hash = Hash[0x44&HASHMASK]; hash; hash = hash->next) {
  245.     if (hash->code == 0x44 && hash->qual == 0) {
  246.         if (n) {
  247.         str = (ubyte *)hash->str;
  248.         stat= hash->stat;
  249.         hash->str = "return";
  250.         hash->stat = 1;
  251.         } else {
  252.         if (str == NULL) {
  253.             remhash(0x44, (ubyte)-1, 0);
  254.         } else {
  255.             hash->str = (char *)str;
  256.             hash->stat= stat;
  257.         }
  258.         }
  259.         return(0);
  260.     }
  261.     }
  262.     if (n) {
  263.     addhash(0x44, 1, 0xFF, 0, "return");
  264.     str = NULL;
  265.     }
  266. }
  267.  
  268. void
  269. addhash(code, stat, mask, qual, str)
  270. ubyte code, stat, mask, qual;
  271. ubyte *str;
  272. {
  273.     HASH **p, *hash;
  274.  
  275.     hash = *(p = &Hash[code&HASHMASK]);
  276.     while (hash) {
  277.     if (hash->code == code && hash->qual == qual && hash->mask == mask) {
  278.         if (!hash->stat)
  279.         FreeMem(hash->str, strlen(hash->str)+1);
  280.         goto newstr;
  281.     }
  282.     hash = *(p = &hash->next);
  283.     }
  284.     *p = hash = (HASH *)AllocMem(sizeof(HASH), 0);
  285.     hash->next = NULL;
  286. newstr:
  287.     hash->code = code;
  288.     hash->stat = stat;
  289.     hash->mask = mask;
  290.     hash->qual = qual;
  291.     hash->str = (char *)str;
  292.     if (!stat)                  /* if not static */
  293.     hash->str = (char *)strcpy((char *)AllocMem(strlen(str)+1, MEMF_PUBLIC), str);
  294. }
  295.  
  296.  
  297. remhash(code, mask, qual)
  298. ubyte code, mask, qual;
  299. {
  300.     HASH *hash, **p;
  301.  
  302.     hash = *(p = &Hash[code&HASHMASK]);
  303.     while (hash) {
  304.     if (hash->code == code && hash->qual == qual && hash->mask == mask) {
  305.         if (!hash->stat)
  306.         FreeMem(hash->str, strlen(hash->str)+1);
  307.         *p = hash->next;
  308.         FreeMem(hash, sizeof(HASH));
  309.         return(1);
  310.     }
  311.     hash = *(p = &hash->next);
  312.     }
  313.     return(0);
  314. }
  315.  
  316. char *
  317. keyspectomacro(str)
  318. char *str;
  319. {
  320.     HASH *hash;
  321.     ubyte code, qual;
  322.  
  323.     if (get_codequal(str, &code, &qual)) {
  324.     for (hash = Hash[code&HASHMASK]; hash; hash = hash->next) {
  325.         if (hash->code == code) {
  326.         if (hash->qual == (qual & hash->mask)) {
  327.             return(hash->str);
  328.         }
  329.         }
  330.     }
  331.     }
  332.     return(NULL);
  333. }
  334.  
  335. void
  336. do_map()
  337. {
  338.     ubyte code, qual;
  339.  
  340.     if (get_codequal(av[1], &code, &qual)) {
  341.     addhash(code, 0, 0xFF, qual, av[2]);
  342.     } else {
  343.     title("Unknown Key");
  344.     }
  345. }
  346.  
  347. void
  348. do_unmap()        /* key   */
  349. {
  350.     ubyte code, qual;
  351.  
  352.     if (get_codequal(av[1], &code, &qual)) {
  353.     remhash(code, (ubyte)-1, qual);
  354.     } else {
  355.     title("Unknown Command");
  356.     }
  357. }
  358.  
  359. void
  360. do_clearmap()
  361. {
  362.     resethash();
  363. }
  364.  
  365. /*
  366.  * SAVEMAP  file
  367.  * SAVESMAP file
  368.  */
  369.  
  370. void
  371. do_savemap()
  372. {
  373.     char sysalso;
  374.     char err = 0;
  375.     char buf[256];
  376.     FILE *fi;
  377.     int i;
  378.     HASH *hash;
  379.     ubyte *ptr;
  380.  
  381.     fi = fopen(av[1], "w");
  382.     if (fi) {
  383.     sysalso = av[0][4] == 's';
  384.     for (i = 0; i < HASHSIZE; ++i) {
  385.         for (hash = Hash[i]; hash; hash = hash->next) {
  386.         if (hash->stat == 0 || sysalso) {
  387.             char soc = '(';
  388.             char eoc = ')';
  389.             char ksoc = '(';
  390.             char keoc = ')';
  391.             short len;
  392.  
  393.             for (ptr = (ubyte *)hash->str; *ptr; ++ptr) {
  394.             if (*ptr == '(')
  395.                 break;
  396.             if (*ptr == '\`') {
  397.                 soc = '\`';
  398.                 eoc = '\'';
  399.                 break;
  400.             }
  401.             }
  402.             len = strlen(ptr = cqtoa(hash->code, hash->qual)) - 1;
  403.             if (ptr[len] == '(' || ptr[len] == ')') {
  404.             ksoc = '\`';
  405.             keoc = '\'';
  406.             }
  407.             sprintf(buf, "map %c%s%c %c%s%c\n", ksoc, cqtoa(hash->code, hash->qual), keoc, soc, hash->str, eoc);
  408.             fputs(buf, fi);
  409.         }
  410.         }
  411.     }
  412.     fclose(fi);
  413.     if (err)
  414.         title ("Unable to Write");
  415.     else
  416.         title ("OK");
  417.     } else {
  418.     title("Unable to open file");
  419.     }
  420. }
  421.  
  422. /*
  423.  *  Nitty Gritty.
  424.  *
  425.  *  keyboard_init:  initialize for get_codequal() and cqtoa()
  426.  *  get_codequal:   convert a qualifier-string combo to a keycode and qual.
  427.  *  cqtoa:        convert a keycode and qual to a qual & string
  428.  */
  429.  
  430. #define LN(a,b,c,d)  ((a<<24)|(b<<16)|(c<<8)|d)
  431.  
  432. static long lname[] = {
  433.     LN('e','s','c', 0  ), LN('f','1', 0 , 0  ), LN('f','2', 0 , 0  ),
  434.     LN('f','3', 0 , 0  ), LN('f','4', 0 , 0  ), LN('f','5', 0 , 0  ),
  435.     LN('f','6', 0 , 0  ), LN('f','7', 0 , 0  ), LN('f','8', 0 , 0  ),
  436.     LN('f','9', 0 , 0  ), LN('f','1','0', 0  ), LN('d','e','l', 0  ),
  437.     LN('b','a','c', 0  ), LN('b','s', 0 , 0  ), LN('t','a','b', 0  ),
  438.     LN('h','e','l', 0  ), LN('r','e','t', 0  ), LN('u','p', 0 , 0  ),
  439.     LN('d','o','w', 0  ), LN('r','i','g', 0  ), LN('l','e','f', 0  ),
  440.     LN('e','n','t', 0  ), LN('n','k','-', 0  ), LN('n','k','.', 0  ),
  441.     LN('n','k','0', 0  ),   /* 24 */
  442.     LN('n','k','1', 0  ), LN('n','k','2', 0  ), LN('n','k','3', 0  ),
  443.     LN('n','k','4', 0  ), LN('n','k','5', 0  ), LN('n','k','6', 0  ),
  444.     LN('n','k','7', 0  ), LN('n','k','8', 0  ), LN('n','k','9', 0  ),
  445.     LN('n','k','(', 0  ), LN('n','k',')', 0  ), LN('n','k','/', 0  ), /*34-36*/
  446.     LN('n','k','*', 0  ), LN('n','k','+', 0  ),
  447.     LN('l','m','b',0xE8), LN('m','m','b',0xEA), LN('r','m','b',0xE9),
  448.     LN('m','m','o',QMOVE),
  449.     0
  450. };
  451.  
  452.  
  453. /*
  454.  *  ESC:    x1B
  455.  *  FUNCKEYS:    x9B 30 7E to x9B 39 7E
  456.  *  DEL:    x7E
  457.  *  BS:     x08
  458.  *  TAB:    x09
  459.  *  RETURN:    x0D
  460.  *  HELP    x9B 3F 7E
  461.  *  UP/D/L/R    x9B 41/42/44/43
  462.  *  NK0-9,-,.,ENTER
  463.  *
  464.  *  Mouse buttons
  465.  */
  466.  
  467. void
  468. keyboard_init()
  469. {
  470.     static struct InputEvent ievent = { NULL, IECLASS_RAWKEY };
  471.     ubyte buf[32];
  472.     short i, len;
  473.  
  474.     lname[16] |= 0x44;
  475.     lname[21] |= 0x43;
  476.  
  477.     for (i = 0; i < 128; ++i) {
  478.     ievent.ie_Code = i;
  479.     ievent.ie_Qualifier = 0;
  480.     ievent.ie_position.ie_addr = NULL;
  481.     len = RawKeyConvert(&ievent,buf,32,NULL);
  482.     switch(len) {
  483.     case 1:     /*    ESC/DEL/BS/TAB/NKx  */
  484.         if ((buf[0] & 0x7F) >= 32 && (buf[0] & 0x7F) < 127)
  485.         ctoa[i] = buf[0];
  486.         switch(buf[0]) {
  487.         case 0x1B:    lname[ 0] |= i; break;
  488.         case 0x7F:    lname[11] |= i; break;
  489.         case 0x09:    lname[14] |= i; break;
  490.         case 0x08:    lname[12] |= i; lname[13] |= i; break;
  491.         case '(': if (i > 0x3A) lname[34] |= i; break;
  492.         case ')': if (i > 0x3A) lname[35] |= i; break;
  493.         case '/': if (i > 0x3A) lname[36] |= i; break;
  494.         case '*': if (i > 0x3A) lname[37] |= i; break;
  495.         case '-': if (i > 0x3A) lname[22] |= i; break;
  496.         case '+': if (i > 0x3A) lname[38] |= i; break;
  497.         case '.': if (i > 0x3A) lname[23] |= i; break;
  498.         default:
  499.         if (i >= 0x0F && buf[0] >= '0' && buf[0] <= '9')
  500.             lname[24+buf[0]-'0'] |= i;
  501.         }
  502.         break;
  503.     case 2:     /*    cursor            */
  504.         if (buf[0] == 0x9B) {
  505.         switch(buf[1]) {
  506.         case 0x41:  lname[17] |= i;  break;
  507.         case 0x42:  lname[18] |= i;  break;
  508.         case 0x43:  lname[19] |= i;  break;
  509.         case 0x44:  lname[20] |= i;  break;
  510.         }
  511.         }
  512.         break;
  513.     case 3:     /*    function/help        */
  514.         if (buf[0] == 0x9B && buf[2] == 0x7E) {
  515.         if (buf[1] == 0x3F)
  516.             lname[15] |= i;
  517.         if (buf[1] >= 0x30 && buf[1] <= 0x39)
  518.             lname[buf[1]-0x30+1] |= i;
  519.         }
  520.         break;
  521.     }
  522.     }
  523.     for (i = 0; i < 128; ++i) {
  524.     ievent.ie_Code = i;
  525.     ievent.ie_Qualifier = IEQUALIFIER_LSHIFT;
  526.     ievent.ie_position.ie_addr = NULL;
  527.     len = RawKeyConvert(&ievent,buf,32,NULL);
  528.     if (len == 1)
  529.         cstoa[i] = buf[0];
  530.     }
  531.     {
  532.     ubyte code, qual;
  533.     get_codequal("c", &code, &qual);
  534.     CtlC = code;
  535.     }
  536. }
  537.  
  538.  
  539. ubyte *
  540. cqtoa(code, qual)
  541. int qual;
  542. {
  543.     static ubyte buf[32];
  544.     ubyte *ptr = buf;
  545.     int i;
  546.  
  547.     if (qual & QUAL_SHIFT)
  548.     *ptr++ = 's';
  549.     if (qual & QUAL_CTRL)
  550.     *ptr++ = 'c';
  551.     if (qual & QUAL_ALT)
  552.     *ptr++ = 'a';
  553.     if (qual & QUAL_AMIGA)
  554.     *ptr++ = 'A';
  555.     if (qual & QUAL_LMB)
  556.     *ptr++ = 'L';
  557.     if (qual & QUAL_MMB)
  558.     *ptr++ = 'M';
  559.     if (qual & QUAL_RMB)
  560.     *ptr++ = 'R';
  561.     if (qual)
  562.     *ptr++ = '-';
  563.     for (i = 0; i < sizeof(lname)/sizeof(lname[0]); ++i) {
  564.     if ((lname[i]&0xFF) == code) {
  565.         *ptr++ = (lname[i]>>24);
  566.         *ptr++ = (lname[i]>>16);
  567.         *ptr++ = (lname[i]>>8);
  568.         break;
  569.     }
  570.     }
  571.     if (i == sizeof(lname)/sizeof(lname[0]))
  572.     *ptr++ = ctoa[code];
  573.     *ptr++ = 0;
  574.     return(buf);
  575. }
  576.  
  577.  
  578. get_codequal(str, pcode, pqual)
  579. ubyte *pcode, *pqual;
  580. ubyte *str;
  581. {
  582.     char *base = str;
  583.     ubyte qual;
  584.     short i;
  585.  
  586.     qual = 0;
  587.     if (strlen(str) > 1) {
  588.     for (; *str && *str != '-'; ++str) {
  589.         if (*str == 's')
  590.         qual |= QUAL_SHIFT;
  591.         if (*str == 'c')
  592.         qual |= QUAL_CTRL;
  593.         if (*str == 'a')
  594.         qual |= QUAL_ALT;
  595.         if (*str == 'A')
  596.         qual |= QUAL_AMIGA;
  597.         if (*str == 'L')
  598.         qual |= QUAL_LMB;
  599.         if (*str == 'M')
  600.         qual |= QUAL_MMB;
  601.         if (*str == 'R')
  602.         qual |= QUAL_RMB;
  603.         if (!qual)
  604.         goto notqual;
  605.     }
  606.     if (*str == 0) {
  607.         qual = 0;
  608.         str = base;
  609.     } else {
  610.         ++str;
  611.     }
  612.     }
  613. notqual:
  614.     if (strlen(str) != 1) {           /* long name   */
  615.     short shift = 24;
  616.     long mult = 0;
  617.     ubyte c;
  618.  
  619.     *pqual = qual;
  620.     while ((c = *str) && shift >= 8) {
  621.         if (c >= 'A' && c <= 'Z')
  622.         c = c - 'A' + 'a';
  623.         mult |= c << shift;
  624.         shift -= 8;
  625.         ++str;
  626.     }
  627.     for (i = 0; lname[i]; ++i) {
  628.         if (mult == (lname[i] & 0xFFFFFF00)) {
  629.         *pcode = lname[i] & 0xFF;
  630.         return(1);
  631.         }
  632.     }
  633.     } else {            /*    single character keycap */
  634.     for (i = 0; i < sizeof(ctoa); ++i) {
  635.         if (*str == ctoa[i]) {
  636.         *pcode = i;
  637.         *pqual = qual;
  638.         return(1);
  639.         }
  640.     }
  641.     for (i = 0; i < sizeof(cstoa); ++i) {
  642.         if (*str == cstoa[i]) {
  643.         *pcode = i;
  644.         *pqual = qual|QUAL_SHIFT;
  645.         return(1);
  646.         }
  647.     }
  648.     }
  649.     return(0);
  650. }
  651.  
  652.